package org.rainwalk.bill.controller;


import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.rainwalk.bill.api.model.Response;
import org.rainwalk.bill.api.model.ResponseCode;
import org.rainwalk.bill.config.WxMaConfiguration;
import org.rainwalk.bill.config.WxMaProperties;
import org.rainwalk.bill.entity.AppUser;
import org.rainwalk.bill.entity.Token;
import org.rainwalk.bill.entity.WechatUser;
import org.rainwalk.bill.model.dto.LoginDTO;
import org.rainwalk.bill.model.enums.AppUserAuthorizedEnum;
import org.rainwalk.bill.model.enums.TokenLoginTypeEnum;
import org.rainwalk.bill.model.vo.LoginVO;
import org.rainwalk.bill.service.IAppUserService;
import org.rainwalk.bill.service.IMailService;
import org.rainwalk.bill.service.ITokenService;
import org.rainwalk.bill.service.IWechatUserService;
import org.rainwalk.bill.util.IdGenerator;
import org.rainwalk.bill.util.RequestUtil;
import org.rainwalk.bill.util.TimeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;

/**
 * <p>
 * 登陆凭证 前端控制器
 * </p>
 *
 * @author 趁雨行
 * @since 2021-02-18
 */
@Api(tags = "权限模块")
@Slf4j
@RestController
@RequestMapping("/token")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class TokenController {

    @Value("${const.token.header}")
    private String tokenName;

    private final IAppUserService userService;

    private final IWechatUserService wechatUserService;

    private final ITokenService tokenService;

    @Autowired(required = false)
    private IMailService mailService;

    private final WxMaProperties wxMaProperties;


    @ApiOperation(value = "pc登录")
    @PostMapping
    public Response login(@RequestBody @Validated LoginDTO dto, HttpServletRequest request) {
        AppUser appUser = userService.getOne(new LambdaQueryWrapper<AppUser>()
                .eq(AppUser::getUsername, dto.getUsername()));

        if (appUser == null || !BCrypt.checkpw(dto.getPassword(), appUser.getPassword())) {
            return Response.fail(ResponseCode.PARAMS_VERITY_FAIL, "账号/密码错误");
        }
        if (! AppUserAuthorizedEnum.AUTHORIZED.getValue().equals(appUser.getAuthorized())) {
            return Response.fail(ResponseCode.PARAMS_VERITY_FAIL, "账户已禁用");
        }

        //添加token
        Token token = new Token();
        token.setId(IdGenerator.generateId());
        token.setUserId(appUser.getId());
        token.setRefreshTime(TimeUtil.getNow());
        token.setIp(RequestUtil.getRemoteAddr(request));
        token.setLoginType(TokenLoginTypeEnum.PC.getValue());
        if (mailService != null) {
            mailService.loginNotify(token);
        }
        tokenService.save(token);

        LoginVO loginVO = new LoginVO();
        loginVO.setName(appUser.getUsername());
        loginVO.setHeader(tokenName);
        loginVO.setToken(token.getId());
        log.info("登录完成");
        return Response.success("登陆成功", loginVO);
    }

    @ApiOperation(value = "pc登出")
    @DeleteMapping
    public Response logout(HttpServletRequest request) {
        String token = request.getHeader(tokenName);
        tokenService.banById(token);
        return Response.success("退出成功");
    }

    /**
     * 小程序登录
     * @return
     */
    @ApiOperation(value = "小程序登录")
    @ApiImplicitParam(value = "个人信息码", name = "code", dataTypeClass = String.class, paramType = "path", required = true, example = "12354545")
    @PostMapping("/{code}")
    public Response loginFromWechat(@PathVariable String code, HttpServletRequest request) {
        //获取openid
        String appid = wxMaProperties.getConfigs().get(0).getAppid();
        final WxMaService wxService = WxMaConfiguration.getMaService(appid);
        try {
            WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(code);

            //根据openid获取绑定用户
            WechatUser wechatUser = wechatUserService.getById(session.getOpenid());
            String appUserId = wechatUser != null ? wechatUser.getUserId() : "1";
            AppUser appUser = userService.getById(appUserId);
            if (appUser == null) {
                return Response.fail(ResponseCode.PARAMS_VERITY_FAIL, "登陆失败，用户不存在");
            }

            //添加token
            Token token = new Token();
            token.setId(IdGenerator.generateId());
            token.setUserId(appUser.getId());
            token.setRefreshTime(TimeUtil.getNow());
            token.setIp(RequestUtil.getRemoteAddr(request));
            token.setSessionKey(session.getSessionKey());
            token.setOpenid(session.getOpenid());
            token.setLoginType(TokenLoginTypeEnum.WECHAT_MINI_APP.getValue());
            tokenService.save(token);

            //构建响应结构
            LoginVO loginVO = new LoginVO();
            loginVO.setName(appUser.getUsername());
            loginVO.setHeader(tokenName);
            loginVO.setToken(token.getId());
            return Response.success("登陆成功", loginVO);
        } catch (WxErrorException e) {
            log.error(e.getMessage(), e);
            return Response.fail(ResponseCode.PARAMS_VERITY_FAIL, "登陆失败");
        }
    }



}
